# -*- coding: utf-8 -*-
# @Author: Jerry
# @Date:   2022-02-23 10:32:29
# @Last Modified by:   Jerry
# @Last Modified time: 2022-03-01 15:31:11
import cv2 as cv
import numpy as np
import os
rootpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
datapath = os.path.join(rootpath,'data')
imgpath = lambda name: os.path.join(datapath,name)

# **********
'''
在本教程中，你将学习如何将图像从一个色彩空间转换到另一个，像BGR↔灰色，BGR↔HSV等
除此之外，我们还将创建一个应用程序，以提取视频中的彩色对象
你将学习以下功能：cv.cvtColor，**cv.inRange**等。
'''

# **********
'''
改变颜色空间
OpenCV中有超过150种颜色空间转换方法。
但是我们将研究只有两个最广泛使用的,BGR↔灰色和BGR↔HSV。
颜色转换，使用cv函数cvtColor(input_image, flag)，其中flag决定转换的类型。
BGR→灰度转换，我们使用标志cv.COLOR_BGR2GRAY。
类似地，对于BGR→HSV，我们使用标志cv.COLOR_BGR2HSV。要获取其他标记，只需在Python终端中运行以下命令:
'''

flags = [i for i in dir(cv) if i.startswith('COLOR_')]
# print flags

'''HSV的色相范围为[0,179]，饱和度范围为[0,255]，值范围为[0,255]。
不同的软件使用不同的规模。因此，如果你要将OpenCV值和它们比较，你需要将这些范围标准化。'''
img1 = cv.imread(imgpath('messi5.jpg'))
img1gray = cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
img1hsv = cv.cvtColor(img1,cv.COLOR_BGR2HSV)
# cv.imshow('BGR',img1)
# cv.imshow('gray',img1gray)
# cv.imshow('hsv',img1hsv)
# cv.waitKey(0)
# cv.destroyAllWindows()

# **********
'''
对象追踪
使用HSV来提取一个有颜色的对象。在HSV中比在BGR颜色空间中更容易表示颜色。
以下应用程序中，将尝试提取一个蓝色的对象
方法如下:
    取视频的每一帧
    转换从BGR到HSV颜色空间
    我们对HSV图像设置蓝色范围的阈值
    现在单独提取蓝色对象，我们可以对图像做任何我们想做的事情。
'''
cap = cv.VideoCapture(0) # 访问硬件设备需有管理员权限
while True:
    # 读取帧
    _,frame = cap.read()
    # 转换颜色空间 BGR 到 HSV
    hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
    # 定义HSV中蓝色的范围，颜色、深浅、明暗
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    # 设置HSV的阈值使得只取蓝色
    mask = cv.inRange(hsv,lower_blue,upper_blue)
    # 将掩膜和图像逐像素相加
    res = cv.bitwise_and(frame,frame,mask=mask) # frame还是BGR色域，而mask可以输说是hsv色域，这两个运算奇了点？
    # 显示图像
    cv.imshow('frame',frame)
    cv.imshow('mask',mask)
    cv.imshow('res',res)
    if cv.waitKey(5)&0xFF==27: # ctrl + q
        break
cv.destroyAllWindows()


# **********
'''
如何找到要追踪的HSV值？
这是在stackoverflow.com上发现的一个常见问题。
它非常简单，你可以使用相同的函数 cv.cvtColor()。
你只需传递你想要的BGR值，而不是传递图像。
例如，要查找绿色的HSV值，请在Python终端中尝试以下命令:
'''
green = np.uint8([[[0,255,0]]])
hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
print hsv_green # [[[ 60 255 255]]]
# 进而把[H-10,100,100]和[H+10,255,255]分别作为下界和上界


# **********
'''
颜色空间：RGB，CMY，HSV，HSL，Lab详解
https://www.cnblogs.com/wangyblzu/p/5710715.html
https://blog.csdn.net/taily_duan/article/details/51506776
https://blog.csdn.net/taily_duan/article/details/51886019

常见的颜色空间有：
RGB:是最常见的面向硬件设备的彩色模型，它是人的视觉系统密切相连的模型，根据人眼结构，
所有的颜色都可以看做是3种基本颜色——红r、绿g、蓝b的不同比例的组合。
国际照度委员会CIE规定的红绿蓝三种基本色的波长分别为700nm、546.1nm、435.8nm。

RGB模型空间是一个正方体，三维坐标系中的xyz三轴对应BGR三色
原点对应黑色，离原点最远的顶点对应白色，从黑到白的灰度分布值在体对角线上。

一般为方便起见，将立方体归一化为单位立方体，这样所有的RGB值都在区间[0,1]之中。
根据这个模型，每幅图像包括3个独立的基色平面，每种颜色亮度用0-255表示，
3种颜色通道的变化以及他们相互之间的叠加可得到1670多万种颜色（2563=16777216）
'''

# **********
'''
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间,
也称六角锥体模型(Hexcone Model)。、这个模型中颜色的参数分别是：色调（H），饱和度（S），亮度（V）。
色调H：用角度度量，取值范围为0°～360°，从红色开始按逆时针方向计算，红色为0°，绿色为120°,蓝色为240°。
      它们的补色是：黄色为60°，青色为180°,品红为300°；
饱和度S：取值范围为0.0～1.0；
亮度V：取值范围为0.0(黑色)～1.0(白色)。
RGB和CMY颜色模型都是面向硬件的，而HSV（Hue Saturation Value）颜色模型是面向用户的。
HSV模型的三维表示从RGB立方体演化而来。
设想从RGB沿立方体对角线的白色顶点向黑色顶点观察，就可以看到立方体的六边形外形。
六边形边界表示色彩，水平轴表示纯度，明度沿垂直轴测量。

一般对颜色空间的图像进行有效处理都是在HSV空间进行的，然后对于基本色中对应的HSV分量需要给定一个严格的范围，
下面是通过实验计算的模糊范围
H:  0— 180
S:  0— 255
V:  0— 255

HSV：HSV颜色空间是孟塞尔彩色空间的简化形式，是一种基于感知的颜色模型。
它将彩色信号分为3种属性：色调（Hue,H），饱和度（Saturation,S），亮度（Value,V）。
色调表示从一个物体反射过来的或透过物体的光波长，也就是说，色调是由颜色的名称来辨别的，如红、黄、蓝；
亮度是颜色的明暗程度；
饱和度是颜色的深浅，如深红、浅红。
HSV颜色空间反映了人观察色彩的方式，具有两个显著的特点：
    亮度分量与图像的彩色信息无关
    “色调”和“饱和度”分量与人感受颜色的方式是紧密相连的
其颜色模型为一个锥形，顶点为黑色
    沿截面圆半径方向的值变化为饱和度
    沿截面圆逆时针方向的值变化为色调
    从定点到底面上的值变化为亮度
'''

